{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Quantum Algorithms (Intro) in Qiskit (Deutsch's)\n",
    "A real algorithm, one of the first ever created, will be implemented in Qiskit.\n",
    "\n",
    "Start by some typical setup and definition of useful functions, which you are encouraged to look at.\n",
    "\n",
    "Then, head to the [exercises start](#Exercises-Start-Here) to start coding!\n",
    "\n",
    "![Matrix Oracle](oracle.jpg)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "from qiskit import QuantumCircuit, ClassicalRegister, QuantumRegister\n",
    "from qiskit import execute"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Choose the drawer you like best:\n",
    "from qiskit.tools.visualization import matplotlib_circuit_drawer as draw\n",
    "#from qiskit.tools.visualization import circuit_drawer as draw"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "from qiskit import IBMQ\n",
    "IBMQ.load_accounts() # make sure you have setup your token locally to use this"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "%matplotlib inline"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Utils for visualizing experimental results"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "import matplotlib.pyplot as plt\n",
    "\n",
    "def show_results(D):\n",
    "    # D is a dictionary with classical bits as keys and count as value\n",
    "    # example: D = {'000': 497, '001': 527}\n",
    "    plt.bar(range(len(D)), list(D.values()), align='center')\n",
    "    plt.xticks(range(len(D)), list(D.keys()))\n",
    "    plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Utils for executing circuits"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Aer backends:  [<QasmSimulator('qasm_simulator') from Aer()>, <QasmSimulatorPy('qasm_simulator_py') from Aer()>, <StatevectorSimulator('statevector_simulator') from Aer()>, <StatevectorSimulatorPy('statevector_simulator_py') from Aer()>, <UnitarySimulator('unitary_simulator') from Aer()>, <CliffordSimulator('clifford_simulator') from Aer()>]\n"
     ]
    }
   ],
   "source": [
    "from qiskit import Aer\n",
    "# See a list of available local simulators\n",
    "print(\"Aer backends: \", Aer.backends())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "IBMQ Backends:  [<IBMQBackend('ibmqx4') from IBMQ()>, <IBMQBackend('ibmqx5') from IBMQ()>, <IBMQBackend('ibmqx2') from IBMQ()>, <IBMQBackend('ibmq_16_melbourne') from IBMQ()>, <IBMQBackend('ibmq_qasm_simulator') from IBMQ()>]\n"
     ]
    }
   ],
   "source": [
    "# see a list of available remote backends (these are freely given by IBM)\n",
    "print(\"IBMQ Backends: \", IBMQ.backends())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Execute locally"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [],
   "source": [
    "# execute circuit and either display a histogram of the results\n",
    "def execute_locally(qc, draw_circuit=False, show_results=False):\n",
    "    # Compile and run the Quantum circuit on a simulator backend\n",
    "    backend_sim = Aer.get_backend('qasm_simulator')\n",
    "    job_sim = execute(qc, backend_sim)\n",
    "    result_sim = job_sim.result()\n",
    "    result_counts = result_sim.get_counts(qc)\n",
    "    \n",
    "    if draw_circuit or show_results: # Print the results\n",
    "        print(\"simulation: \", result_sim, result_counts)\n",
    "    \n",
    "    if draw_circuit: # draw the circuit\n",
    "        draw(qc)\n",
    "    elif show_results: # or show the results\n",
    "        show_results(result_counts)\n",
    "    return result_counts"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Execute remotely"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [],
   "source": [
    "from qiskit.backends.ibmq import least_busy\n",
    "import time\n",
    "# Compile and run on a real device backend\n",
    "def execute_remotely(qc, draw_circuit=False, show_results=False):\n",
    "    if draw_circuit: # draw the circuit\n",
    "        draw(qc)\n",
    "    try:\n",
    "        # select least busy available device and execute.\n",
    "        least_busy_device = least_busy(IBMQ.backends(simulator=False))\n",
    "        print(\"Running on current least busy device: \", least_busy_device)\n",
    "\n",
    "        # running the job\n",
    "        job_exp = execute(qc, backend=least_busy_device, shots=1024, max_credits=10)\n",
    "\n",
    "        lapse, interval = 0, 10\n",
    "        while job_exp.status().name != 'DONE':\n",
    "            print('Status @ {} seconds'.format(interval * lapse))\n",
    "            print(job_exp.status())\n",
    "            time.sleep(interval)\n",
    "            lapse += 1\n",
    "        print(job_exp.status())\n",
    "        exp_result = job_exp.result()\n",
    "        result_counts = exp_result.get_counts(qc)\n",
    "\n",
    "        # Show the results\n",
    "        print(\"experiment: \", exp_result, result_counts)\n",
    "        if show_results: # show the results\n",
    "            show_results(result_counts)\n",
    "        return result_counts\n",
    "    except:\n",
    "        print(\"All devices are currently unavailable.\")\n",
    "        return {}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Building the circuit"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [],
   "source": [
    "def new_circuit(size):\n",
    "    # Create a Quantum Register with size qubits\n",
    "    qr = QuantumRegister(size)\n",
    "\n",
    "    # Create a Classical Register with size bits\n",
    "    cr = ClassicalRegister(size)\n",
    "\n",
    "    # Create a Quantum Circuit acting on the qr and cr register\n",
    "    return qr, cr, QuantumCircuit(qr, cr)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Our secret Oracles"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [],
   "source": [
    "ERROR_MESSAGE = \"Looks like your Deutsch has a bug\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [],
   "source": [
    "def quantum_oracle_1(qr, cr, circuit):\n",
    "    pass"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [],
   "source": [
    "def quantum_oracle_2(qr, cr, circuit):\n",
    "    circuit.cx(qr[0], qr[1])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [],
   "source": [
    "def quantum_oracle_3(qr, cr, circuit):\n",
    "    circuit.cx(qr[0], qr[1])\n",
    "    circuit.cx(qr[1], qr[0])\n",
    "    circuit.cx(qr[0], qr[1])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [],
   "source": [
    "def quantum_oracle_4(qr, cr, circuit):\n",
    "    circuit.z(qr[1])\n",
    "    circuit.cx(qr[0], qr[1])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "<h1 align=\"center\">Exercises Start Here</h1>\n",
    "\n",
    "Make sure you ran all the above cells in order, as the following exercises use functions defined and imported above."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Understanding Deutsch's Algorithm\n",
    "If you need go back to the slides, or check other sources, but it is quite important that you get a good grasp on why the algorithm works. Hopefully, these exercises will help achieve that. \n",
    "\n",
    "Firstly, let us look at our goal circuit:\n",
    "![deutsch's circuit](deutsch_algorithm.png)\n",
    "The XOR symbol is meaningful but not realistic, that is actually a measurement, as you may have guessed!!"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Your Task\n",
    "I have defined 4 mysterious **oracles:** `quantum_oracle_1` through `quantum_oracle_4`. (For 2 qubits)\n",
    "\n",
    "You need to find, without looking at their implementation, whether they are **balanced** or **constant** by designing a quantum circuit, just follow the next steps:"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**TASK:** Create a new circuit with 2 qubits using `new_circuit` (very useful to reconstruct your circuit in Jupyter)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [],
   "source": [
    "qr, cr, circuit = new_circuit(2)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**TASK:** Make the necessary modifications on the input qubits (before the Hadamards)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [],
   "source": [
    "# X gate on qubit 1 (bit flip)\n",
    "circuit.x(qr[1]);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**TASK:** Implement the Hadamards on both qubits"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [],
   "source": [
    "circuit.h(qr);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**TASK:** Call our oracle 1: `quantum_oracle_1(CLASSICAL_REGISTER, QUANTUM_REGISTER, YOUR_CURRENT_CIRCUIT)`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [],
   "source": [
    "quantum_oracle_1(qr, cr, circuit)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**TASK:** Implement the Hadamard on qubit 0"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [],
   "source": [
    "circuit.h(qr[0]);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**TASK:** Perform a measurement"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [],
   "source": [
    "# measure the specific qubit\n",
    "circuit.measure(qr[0], cr[0]);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**TASK:** check the result using `execute_locally` test both `True` and `False` for the `draw_circuit` and `show_results` (4 different combinations) option and save the results!\n",
    "\n",
    "(This function has been updated and now returns a dictionary like: `{'00': 524, '11': 500}`)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "simulation:  COMPLETED {'00': 1024}\n"
     ]
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x129259092e8>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# Try both commands:\n",
    "# results = execute_locally(circuit, draw_circuit=False, show_results=False) # silent mode\n",
    "results = execute_locally(circuit, draw_circuit=True, show_results=False)\n",
    "# results = execute_locally(circuit, draw_circuit=False, show_results=True)\n",
    "# results = execute_locally(circuit, draw_circuit=True, show_results=True) # this will be the same as True, False"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**TASK:** Now implement a decision mechanism that will print either `\"CONSTANT\"` or `\"BALANCED\"`, according to what type of oracle `quantum_oracle_1` is!"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CONSTANT\n"
     ]
    }
   ],
   "source": [
    "if '00' in results:\n",
    "    print(\"CONSTANT\")\n",
    "elif '10' in results:\n",
    "    print(\"BALANCED\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**TASK:** Take your code and isolate it into a function `get_deutsch_verdict` that has a dictionary with the execution results and returns either `\"CONSTANT\"` or `\"BALANCED\"`, accordingly."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [],
   "source": [
    "def get_deutsch_verdict(res): # should be improved for error handling\n",
    "    if '00' in res:\n",
    "        return \"CONSTANT\"\n",
    "    elif '01' in res:\n",
    "        return \"BALANCED\""
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**TASK:** Call your function with your previous results and print its return value:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CONSTANT\n"
     ]
    }
   ],
   "source": [
    "print(get_deutsch_verdict(results))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Isolate your code into a function\n",
    "**TASK:** Create a function called `deutsch` which receives a `black_box` as an argument and returns either `\"CONSTANT\"` or `\"BALANCED\"` (a stub has already been created for you)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {},
   "outputs": [],
   "source": [
    "def deutsch(black_box):\n",
    "    qr, cr, circuit = new_circuit(2)\n",
    "    circuit.x(qr[1]) # X gate on qubit 1 (bit flip)\n",
    "    circuit.h(qr) # Hadamard on both qubits\n",
    "    \n",
    "    black_box(qr, cr, circuit)\n",
    "    \n",
    "    circuit.h(qr[0]) # Hadamard on interesting qubit\n",
    "    circuit.measure(qr[0], cr[0]) # measure the specific qubit\n",
    "    \n",
    "    results = execute_locally(circuit, draw_circuit=False, show_results=False) # silent mode\n",
    "    return get_deutsch_verdict(results)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**TASK:** Call `deutsch(quantum_oracle_1)` and a `'CONSTANT'` value should appear:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'CONSTANT'"
      ]
     },
     "execution_count": 27,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "deutsch(quantum_oracle_1)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**TASK:** Now that you are confident of your implementation, call it for the following cases to make sure it is! If you have a bug an `AssertionError` will appear"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Test case 1: `quantum_oracle_1`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {},
   "outputs": [],
   "source": [
    "assert deutsch(quantum_oracle_1) == 'CONSTANT', ERROR_MESSAGE"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Test case 2: `quantum_oracle_2`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {},
   "outputs": [],
   "source": [
    "assert deutsch(quantum_oracle_2) == 'BALANCED', \"Looks like your Deutsch has a bug\""
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Test case 3: `quantum_oracle_3`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {},
   "outputs": [],
   "source": [
    "assert deutsch(quantum_oracle_3) == 'BALANCED', \"Looks like your Deutsch has a bug\""
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Test case 4: `quantum_oracle_4`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {},
   "outputs": [],
   "source": [
    "assert deutsch(quantum_oracle_4) == 'CONSTANT', \"Looks like your Deutsch has a bug\""
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Free Flow\n",
    "On your own, try to implement `deutsch_jozsa` which is able to handle multiple qubits (this can your homework for the week!). "
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
